package com.cms.bind_cpmpiler

import com.cms.bind_annotation.BindClick
import com.google.auto.service.AutoService
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.KModifier
import com.squareup.kotlinpoet.TypeSpec
import java.io.File
import javax.annotation.processing.AbstractProcessor
import javax.annotation.processing.Messager
import javax.annotation.processing.ProcessingEnvironment
import javax.annotation.processing.Processor
import javax.annotation.processing.RoundEnvironment
import javax.annotation.processing.SupportedAnnotationTypes
import javax.annotation.processing.SupportedSourceVersion
import javax.lang.model.SourceVersion
import javax.lang.model.element.Element
import javax.lang.model.element.ElementKind
import javax.lang.model.element.TypeElement
import javax.lang.model.util.Elements
import javax.lang.model.util.Types
import javax.tools.Diagnostic

@AutoService(Processor::class)
@SupportedAnnotationTypes("com.cms.bind_annotation.BindClick")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
class BindClickProcessor : AbstractProcessor() {

    private var element: Elements? = null
    private var typeTool: Types? = null
    private var messager: Messager? = null

    private var map: HashMap<Element, MutableList<Element>> = hashMapOf()

    override fun init(processingEnv: ProcessingEnvironment) {
        super.init(processingEnv)
        element = processingEnv.elementUtils
        typeTool = processingEnv.typeUtils
        messager = processingEnv.messager
        messager!!.printMessage(
            Diagnostic.Kind.NOTE,
            "type-----:bindClick"
        )
    }


    override fun process(
        annotations: MutableSet<out TypeElement>?,
        roundEnv: RoundEnvironment?
    ): Boolean {
        messager?.printMessage(
            Diagnostic.Kind.NOTE,
            "type-----:bindClick"
        )
        val elements = roundEnv?.getElementsAnnotatedWith(BindClick::class.java)
        if (elements.isNullOrEmpty()) return false
        val iterator = elements.iterator()

        while (iterator.hasNext()) {
            val next = iterator.next()
            if (next.kind == ElementKind.METHOD) {
                if (map.containsKey(next.enclosingElement)) {
                    map[next.enclosingElement]!!.add(next)
                } else {
                    val list = mutableListOf<Element>()
                    list.add(next)
                    map[next.enclosingElement] = list
                }
            } else {
                messager?.printMessage(Diagnostic.Kind.ERROR, "BindView 注解只能使用在方法上")
                return false
            }
        }
        map.forEach { t, u ->
            //定义java文件
            val fileBuilder = FileSpec.builder("com.cms.processor", "${t.simpleName}Method")

            val classBuilder = TypeSpec.classBuilder("${t.simpleName}Method")
                .addSuperinterface(ClassName.bestGuess(ProcessorConfig.TYPE_METHOD))

            val methodBuilder = FunSpec.builder("invoke")
                .addParameter("target",Any::class)
                .addModifiers(KModifier.OVERRIDE)

            methodBuilder.addStatement("val activity = target as %T",ClassName.bestGuess(t.toString()))


            u.forEach {
                messager?.printMessage(Diagnostic.Kind.NOTE, "BindView "+it.simpleName+"--"
                +it.enclosingElement+"--" +"")
                val bindClick = it.getAnnotation(BindClick::class.java)
               methodBuilder.addStatement("activity.findViewById<%T>("+bindClick.value+").setOnClickListener{ activity."+it.simpleName+"() }",ClassName.bestGuess("android.view.View"))


            }


            val outDir = processingEnv.options[BindViewProcessor.KAPT_KOTLIN_GENERATED_OPTION_NAME]

            fileBuilder.addType(classBuilder.addFunction(methodBuilder.build()).build()).build().writeTo(File(outDir))

        }








        return false
    }
}